#pragma once

#include "utility.h"
#include "HashTable.h"
#include <initializer_list>

namespace qyc
{
	template<class K, class V, class Hash = HashFunc<K>, class Pred = equal_to<K>>
	class unordered_map
	{
		typedef pair<const K, V> data_type;
		struct MapKeyOfValue
		{
			const K& operator()(const data_type& kv)
			{
				return kv.first;
			}
		};
		typedef hash_bucket::HashTable<K, data_type, MapKeyOfValue, Hash, Pred> hashtable;
		typedef unordered_map<K, V, Hash, Pred> self;
	public:
		typedef typename hashtable::iterator iterator;
		typedef typename hashtable::const_iterator const_iterator;

		unordered_map() = default;
		template<class InputIterator>
		unordered_map(InputIterator first, InputIterator last)
		{
			_ht.insert_range(first, last);
		}
		unordered_map(std::initializer_list<data_type> _Ilist)
		{
			_ht.insert_range(_Ilist.begin(), _Ilist.end());
		}

		iterator begin()
		{
			return _ht.begin();
		}
		iterator end()
		{
			return _ht.end();
		}
		const_iterator begin() const
		{
			return _ht.begin();
		}
		const_iterator end() const
		{
			return _ht.end();
		}

		pair<iterator, bool> insert(const data_type& key)
		{
			return _ht.insert(key);
		}
		pair<iterator, bool> insert(data_type&& key)
		{
			return _ht.insert(qyc::forward<data_type>(key));
		}
		template<class... Args>
		pair<iterator, bool> emplace(Args&&... args)
		{
			return _ht.emplace(args...);
		}
		template<class InputIterator>
		void insert(InputIterator first, InputIterator last)
		{
			_ht.insert_range(first, last);
		}
		V& operator[](const K& key)
		{
			return (_ht.insert(data_type(key, V())).first)->second;
		}
		const V& operator[](const K& key) const
		{
			return (_ht.insert(data_type(key, V())).first)->second;
		}
		void erase(const K& key)
		{
			_ht.erase(key);
		}
		iterator find(const K& key)
		{
			return _ht.find(key);
		}

		void clear()
		{
			_ht.clear();
		}
		bool empty() const
		{
			return _ht.empty();
		}
		size_t size() const
		{
			return _ht.size();
		}
		void swap(self& des)
		{
			_ht.swap(des._ht);
		}
	private:
		hashtable _ht;
	};

	template<class K, class V, class Hash = HashFunc<K>, class Pred = equal_to<K>>
	class unordered_multimap
	{
		typedef pair<const K, V> data_type;
		struct MapKeyOfValue
		{
			const K& operator()(const data_type& kv)
			{
				return kv.first;
			}
		};
		typedef hash_bucket::HashTable<K, data_type, MapKeyOfValue, Hash, Pred> hashtable;
		typedef unordered_multimap<K, V, Hash, Pred> self;
	public:
		typedef typename hashtable::iterator iterator;
		typedef typename hashtable::const_iterator const_iterator;

		unordered_multimap() = default;
		template<class InputIterator>
		unordered_multimap(InputIterator first, InputIterator last)
		{
			_ht.insert_equal_range(first, last);
		}
		unordered_multimap(std::initializer_list<data_type> _Ilist)
		{
			_ht.insert_equal_range(_Ilist.begin(), _Ilist.end());
		}

		iterator begin()
		{
			return _ht.begin();
		}
		iterator end()
		{
			return _ht.end();
		}
		const_iterator begin() const
		{
			return _ht.begin();
		}
		const_iterator end() const
		{
			return _ht.end();
		}

		pair<iterator, bool> insert(const data_type& key)
		{
			return _ht.insert_equal(key);
		}
		pair<iterator, bool> insert(data_type&& key)
		{
			return _ht.insert_equal(qyc::forward<data_type>(key));
		}
		template<class... Args>
		pair<iterator, bool> emplace(Args&&... args)
		{
			return _ht.emplace_equal(args...);
		}
		template<class InputIterator>
		void insert(InputIterator first, InputIterator last)
		{
			_ht.insert_equal_range(first, last);
		}
		void erase(const K& key)
		{
			_ht.erase(key);
		}
		iterator find(const K& key)
		{
			return _ht.find(key);
		}

		void clear()
		{
			_ht.clear();
		}
		bool empty() const
		{
			return _ht.empty();
		}
		size_t size() const
		{
			return _ht.size();
		}
		void swap(self& des)
		{
			_ht.swap(des._ht);
		}
	private:
		hashtable _ht;
	};
}